package com.umfwechat.lightprogram.interceptor;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.umfwechat.common.constant.CacheConsts;
import com.umfwechat.util.AesUtil;
import com.umfwechat.util.DynamicCipher;
import com.umfwechat.util.HashEncrypt;
import com.umfwechat.util.PropertyUtil;
import com.umfwechat.util.RedisUtil;
import com.umfwechat.util.StringUtil;

import com.umfwechat.util.StringReaderUtils;

import net.sf.json.JSONObject;

@Aspect
@Component
public class SafeLayerInterceptor {
	private static final Logger logger = LoggerFactory.getLogger(SafeLayerInterceptor.class);

	/**
	 * 成功
	 */
	private static String success = "0000";
	/**
	 * 解密失败
	 */
	private static String F_CODE_decode = "40000";
	/**
	 * 解密aes失败
	 */
	private static String F_CODE_decode_AES = "40001";
	/**
	 * 解密敏感字段Field失败
	 */
	private static String F_CODE_decode_Field = "40002";

	// KeyID写入配置
	private static String KeyID = PropertyUtil.getProperties("umfWeChatPlat_appConf.properties").getProperty("safeLayer.KeyID");

	private static String AES_SALT = "65bf32b4befebc9768a988ceadc1b7f5";
	private static String AES_IV = "473680038f894b5cce080e6f431e07ef";
	private static int AES_KEY_SIZE = 128;
	private static int AES_ITERATION = 1000;

	  //获取上传图片和敏感字段
	private static String UploadImg_Controllers[] = PropertyUtil.getProperties("umfWeChatPlat_appConf.properties").getProperty("safeLayer.UploadImg_Controllers").split(",");
	private static String NeedEncodeFields[] = PropertyUtil.getProperties("umfWeChatPlat_appConf.properties").getProperty("safeLayer.Sensitive_String").split(",");
		//private static String UploadImg_Controllers[] = { "/merchantDeploy/uploadImg", "/merchantProductDeploy/openPosUpload" };
		//敏感字段
	
/*	private static String UploadImg_Controllers[] = { "/merchantDeploy/uploadImg",
			"/merchantProductDeploy/openPosUpload" };
	private static String[] NeedEncodeFields = { "loginPwd", "newLoginPwd", "newPayPwd", "oldLoginPwd", "payPwd",
			"cardId", "identityCode" };*/

	/**
	 * 安全层拦截 TODO 错误码统一 9990 解密失败 9991 加密失败 9999 安全层错误 00160118 证书更新
	 * 
	 * @param pjp
	 * @return
	 */
	public Object onAround(ProceedingJoinPoint pjp) {
		logger.info("################### 安全层 Start #######################");
		
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();

		String url = request.getRequestURL().toString();
		String uri = request.getRequestURI();
		logger.info("[安全层]请求开始, 各个参数, url: {},   uri: {}", url, uri);

		JSONObject resultJSONObject = new JSONObject();

		// =========================================================解密
		SafeLayerRequest safeRequest = decrtypt(request);
		if (success.equals(safeRequest.getCode())) {
			logger.info("[安全层]解密成功－－>");
			//logger.info("[安全层]解密后明文:" + safeRequest.getData());
			request.setAttribute("_requestData", safeRequest.getData());
		} else {
			//  解密失败
			// KeyId：密钥号（明文）
			String keyId = request.getHeader("keyId");
			if (F_CODE_decode_AES.equals(safeRequest.getCode())) {
				//  aes解密失败
				// keyId不为空，并且与当前k
				if (keyId != null && !KeyID.equals(keyId)) {
					logger.info("[安全层]需要更新证书");
					//TODO
					//获取新证书(新的RSA公钥返回给客户端)
				  /*String certStr = DynamicCipher.rsaReadPubKey();
					String certId = KeyID;*/
					
					/*resultJSONObject.put("certStr", "00160118");
					resultJSONObject.put("certId", KeyID);*/
					resultJSONObject.put("retCode", "00160118");
					resultJSONObject.put("retMsg", "更新证书");
					return encodeResult(resultJSONObject);
				}
			} else if (F_CODE_decode_Field.equals(safeRequest.getCode())) {
				// TODO 敏感字段解密失败
				//敏感字段解密失败要做哪些任务（RSA解密失败），获取新证书
				resultJSONObject.put("retCode", "9990");
				resultJSONObject.put("retMsg", "敏感字段解密失败");
				return encodeResult(resultJSONObject);
			}

			resultJSONObject.put("retCode", "9990");
			resultJSONObject.put("retMsg", "系统维护中，请稍后再试");
			return encodeResult(resultJSONObject);
		}

		// =========================================================业务处理
		// result的值就是被拦截方法的返回值,
		Object result = null;
		try {
			
			AuthoInterceptor autho = new AuthoInterceptor();
			PermConfInterceptor pci = new PermConfInterceptor();
			if(autho.process(safeRequest.getData())){
				result = autho.result();
			}else if(pci.permConf(safeRequest.getData())){
				result = pci.result();
			}else{
				result = pjp.proceed();
			}
			if (result == null) {
				throw new Exception("[安全层]业务层返回数据为空");
			}
		} catch (Throwable e) {
			logger.info(e.getMessage(), e);
			return encodeResult("9999", "系统维护中，请稍后再试");
		}
		logger.info("请求方法最终返回值"+result);
		System.err.println("请求的出参："+result.toString());
		
		// =========================================================返回结果
		try {
			JSONObject encryptObj = encrypt(result, safeRequest.getAesKey());
			resultJSONObject.putAll(encryptObj);
		} catch (Exception e) {
			logger.info(e.getMessage(), e);
			logger.info("[安全层]加密处理错误");
			return encodeResult("9991", "系统维护中，请稍后再试");
		}

		resultJSONObject.put("retCode", "0000");
		resultJSONObject.put("retMsg", "ok");
		logger.info("################### 安全层 End #######################");
		return encodeResult(resultJSONObject);
	}

	/**
	 * 返回code与msg编码
	 * 
	 * @param jsonObj
	 * @return
	 */
	private JSONObject encodeResult(JSONObject jsonObj) {
		try {
			/*if(!jsonObj.getString("certStr").equals("")&&!jsonObj.getString("certId").equals(""))
			{
				jsonObj.put("certStr", Hex.encodeHexString(jsonObj.getString("certStr").getBytes("UTF-8")));
				jsonObj.put("certId", Hex.encodeHexString(jsonObj.getString("certId").getBytes("UTF-8")));
			}*/
			jsonObj.put("retCode", Hex.encodeHexString(jsonObj.getString("retCode").getBytes("UTF-8")));
			jsonObj.put("retMsg", Hex.encodeHexString(jsonObj.getString("retMsg").getBytes("UTF-8")));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return jsonObj;
	}

	/**
	 * 返回结果
	 * 
	 * @param code
	 * @param msg
	 * @return
	 */
	private JSONObject encodeResult(String code, String msg) {
		JSONObject resultJson = new JSONObject();
		resultJson.put("retCode", code);
		resultJson.put("retMsg", msg);
		return encodeResult(resultJson); // 结果编码
	}

	/**
	 * 加密内容
	 * 
	 * @param rep
	 * @param aesKey
	 * @return
	 * @throws Exception
	 */
	private JSONObject encrypt(Object rep, String aesKey) throws Exception {
		JSONObject resultJson = new JSONObject();

		AesUtil util = new AesUtil(AES_KEY_SIZE, AES_ITERATION);
		String body = JSONObject.fromObject(rep).toString();

		String bodyEncrypt = util.encrypt(AES_SALT, AES_IV, aesKey, body);

		String randomNum = UUID.randomUUID().toString();
		String randomNumEncrypt = util.encrypt(AES_SALT, AES_IV, aesKey, randomNum);

		String signStr = body + randomNum;
		String signResult = HashEncrypt.doEncrypt(signStr, "SHA-1", "UTF-8");
		String signEncrypt = util.encrypt(AES_SALT, AES_IV, aesKey, signResult);

		resultJson.put("randomNum", Hex.encodeHexString(randomNumEncrypt.getBytes("UTF-8")));
		resultJson.put("sign", Hex.encodeHexString(signEncrypt.getBytes("UTF-8")));
		resultJson.put("body", Hex.encodeHexString(bodyEncrypt.getBytes("UTF-8")));

		return resultJson;
	}

	/**
	 * 获取报文 1.图片上传接口，报文信息在[Header]:formData字段, body为图片二进制 2.普通接口字段报文信息在body中
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	private String getRequestBody(HttpServletRequest request) throws IOException {
		// 获取请求体, 如果是图片则获取：formData
		String uri = request.getRequestURI();
		for (String name : UploadImg_Controllers) {
			if (uri.contains(name)) {
				String formData = request.getHeader("formData");
				logger.info("[HTTP] Header - formData:" + formData);
				return formData;
			}
		}
		return StringReaderUtils.readFromIO(request.getInputStream());
	}

	/**
	 * 解密报文
	 * 
	 * @param request
	 * @return
	 */
	private SafeLayerRequest decrtypt(HttpServletRequest request) {
		SafeLayerRequest resultRequest = new SafeLayerRequest();

		String keyId = request.getHeader("keyId");
		String randomNum = request.getHeader("randomNum");
		String ssfe = request.getHeader("ssfe");
		String equInfo = request.getHeader("equInfo");
		String safeChick = request.getHeader("safeChick");
		String sign = request.getHeader("sign");

		logger.info("[HTTP] Header - keyId:" + keyId);
		logger.info("[HTTP] Header - randomNum:" + randomNum);
		logger.info("[HTTP] Header - ssfe:" + ssfe);
		logger.info("[HTTP] Header - equInfo:" + equInfo);
		logger.info("[HTTP] Header - safeChick:" + safeChick);
		logger.info("[HTTP] Header - sign:" + sign);

		String reqJSON = null;
		try {
			reqJSON = getRequestBody(request);
			logger.info("[HTTP] Body:" + reqJSON);
		} catch (IOException e) {
			logger.info(e.getMessage(), e);
			resultRequest.setCode(F_CODE_decode);
			return resultRequest;
		}

		String aesKey = null;
		try {
			//TODO
			aesKey = DynamicCipher.rsaDecrypt(Base64.decodeBase64(ssfe),"");
		} catch (Exception e) {
			logger.info(e.getMessage(), e);
			resultRequest.setCode(F_CODE_decode_AES);
		}

		logger.info("安全层解密  aesKey:" + aesKey);

		try {
			JSONObject param = JSONObject.fromObject(reqJSON);
			String secretData = (String) param.get("secretData");
			AesUtil util = new AesUtil(AES_KEY_SIZE, AES_ITERATION);

			String secretDataDecrypt = util.decrypt(AES_SALT, AES_IV, aesKey, secretData);
			logger.info("secretData明文:" + secretDataDecrypt);

			String equInfoDecry = util.decrypt(AES_SALT, AES_IV, aesKey, equInfo);
			logger.info("equInfo明文:" + equInfoDecry);

			String safeChickDecry = util.decrypt(AES_SALT, AES_IV, aesKey, safeChick);
			logger.info("safeChick明文:" + safeChickDecry);

			String randomNumDecry = util.decrypt(AES_SALT, AES_IV, aesKey, randomNum);
			logger.info("randomNum明文:" + randomNumDecry);

			String signDecry = util.decrypt(AES_SALT, AES_IV, aesKey, sign);
			logger.info("sign明文:" + signDecry);

			String signStr = keyId + aesKey + equInfoDecry + safeChickDecry + randomNumDecry;

			String signResult = HashEncrypt.doEncrypt(signStr, "SHA-1", "UTF-8");
			logger.info("报文签名:" + signResult);

			// 解密敏感字段
			JSONObject secretDataJson = null;
			try {
				secretDataJson = decrtyptField(secretDataDecrypt);
			} catch (Exception e) {
				logger.info(e.getMessage(), e);
				resultRequest.setCode(F_CODE_decode_Field);
				return resultRequest;
			}

			if (signResult.equals(signDecry)) {
				resultRequest.setData(secretDataJson.toString());
				resultRequest.setAesKey(aesKey);
				resultRequest.setCode("0000");
				return resultRequest;
			}
		} catch (Exception e) {
			logger.info(e.getMessage(), e);
			resultRequest.setCode(F_CODE_decode);
		}
		return resultRequest;
	}

	private JSONObject decrtyptField(String secretDataDecrypt) throws Exception {
		// 解密敏感字段
		JSONObject secretDataJson = JSONObject.fromObject(secretDataDecrypt);
		for (String field : NeedEncodeFields) {
			if (secretDataJson.containsKey(field)) {
				//String fieldStr = (String) secretDataJson.get(field);
				String fieldStr = secretDataJson.getString(field);
				if((!"".equals(fieldStr))&&(!"null".equalsIgnoreCase(fieldStr))){
				// 解密敏感字段用新的RSA密钥
				String fieldDecrypt = DynamicCipher.rsaDecrypt(Base64.decodeBase64(fieldStr),"sense");
				logger.info("[field] {}密文:{}", field, fieldStr);
				//logger.info("[field] {}明文:{}", field, fieldDecrypt);
				// 更新字段
				secretDataJson.put(field, fieldDecrypt);
				}
			}
		}
		return secretDataJson;
	}
}
